package com.zcyh.exam.service.education;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zcyh.exam.config.exception.BusinessException;
import com.zcyh.exam.constants.EnumConstants;
import com.zcyh.exam.job.quartz.config.quartz.QuartzTaskScheduler;
import com.zcyh.exam.mapper.CommonMapper;
import com.zcyh.exam.mapper.education.TestPaperInfoMapper;
import com.zcyh.exam.model.common.PageInfo;
import com.zcyh.exam.model.common.ResultCode;
import com.zcyh.exam.model.dto.TestPaperInfoDto;
import com.zcyh.exam.model.dto.TestPaperQuestionDto;
import com.zcyh.exam.model.entity.*;
import com.zcyh.exam.model.request.PageParam;
import com.zcyh.exam.model.request.TestPaperQuestionRequest;
import com.zcyh.exam.model.response.TestPaperInfoVo;
import com.zcyh.exam.service.BaseService;
import com.zcyh.exam.utils.CodeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zengjintao
 * @version 1.0
 * @create_at 2020/11/20 21:22
 */
@Service
public class TestPaperInfoService extends BaseService<TestPaperInfoMapper, TestPaperInfo> {

    @Autowired
    private TestPaperQuestionInfoService testPaperQuestionInfoService;

    @Autowired
    private TestPaperUserService testPaperUserService;

    @Autowired
    private TestPaperAreaService testPaperAreaService;

    @Autowired
    private QuartzTaskScheduler quartzTaskScheduler;

    @Autowired
    private ExamInfoService examInfoService;


    @Autowired
    private CommonMapper commonMapper;
    /**
     * 试卷分页列表
     * @param pageParam
     * @return
     */
    public PageInfo<TestPaperInfoDto> selectPageList(PageParam pageParam,
                                                     String areaCodes,
                                                     String name,
                                                     String startTime,String endTime,Integer status,boolean publishFlag
                                                     ) {
        Set<String> codesGroups = null;
        if(StrUtil.isNotBlank(areaCodes)){
            String[] split = areaCodes.split(",");
            List<String> strings = Arrays.asList(split);
            Set<String> finalCodesGroups = new HashSet<>();
            strings.forEach(x->{
                finalCodesGroups.addAll(CodeUtil.getCodesGroups(x));
            });
            codesGroups = finalCodesGroups;
        }
        Page<TestPaperInfoDto> page = new Page<>(pageParam.getPageNumber(), pageParam.getPageSize());
        return selectPage(baseMapper.selectPageList(page,codesGroups,startTime,endTime,name,status,publishFlag));
    }

    /**
     * 查询学员的试卷列表
     * @param pageParam
     * @return
     */
    public PageInfo<TestPaperInfoDto> selectStudentPageList(PageParam pageParam) {
        String userId = getUserId();
        String userAreaCode = commonMapper.getUserAreaCode(userId);
        List<String> codesGroups = CodeUtil.getCodesGroups(userAreaCode);
        Page<TestPaperInfoDto> page = new Page<>(pageParam.getPageNumber(), pageParam.getPageSize());
        return selectPage(baseMapper.selectStudentPageList(page, codesGroups,userId));
    }

    /**
     * 获取试卷试题列表
     * @param pageParam
     * @param testPaperQuestionRequest
     * @return
     */
    public PageInfo<TestPaperQuestionDto> selectPaperQuestionList(PageParam pageParam, TestPaperQuestionRequest testPaperQuestionRequest) {
        Page<TestPaperQuestionDto> page = new Page<>(pageParam.getPageNumber(), pageParam.getPageSize());
        return selectPage(baseMapper.selectPaperQuestionList(page, testPaperQuestionRequest));
    }

    /**
     * 网格员获取试题试卷 -- 等于开始考试
     * @param pageParam
     * @param testPaperInfoId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Object selectStudentPaperQuestionList(PageParam pageParam, String testPaperInfoId) {
        String userId = getUserId();
        TestPaperUser one = testPaperUserService.getOne(Wrappers.<TestPaperUser>lambdaQuery()
                .eq(TestPaperUser::getTestPaperInfoId, testPaperInfoId)
                .eq(TestPaperUser::getUserId, userId)
        );
        TestPaperInfo testPaperInfo = this.getById(testPaperInfoId);

        ExamInfo examInfo = examInfoService.getOne(Wrappers.<ExamInfo>lambdaQuery()
                .eq(ExamInfo::getTestPaperInfoId,testPaperInfoId)
                .eq(ExamInfo::getUserId,userId)
        );
        if(examInfo==null){
            /*初始化网格员考试信息*/
            examInfo = new ExamInfo();
            examInfo.setUserId(userId);
            examInfo.setQuestionNumber(testPaperInfo.getQuestionNumber());
            examInfo.setTestPaperInfoId(testPaperInfoId);
            examInfoService.save(examInfo);
        }
        if(one==null){
            one = new TestPaperUser(userId,getUserInfo().getUserName(),testPaperInfoId,null);
            testPaperUserService.save(one);
        }
        if(one.getStarTime()==null){
            one.setStarTime(DateUtil.date());
            testPaperUserService.updateById(one);

            testPaperInfo.setExamNumber(testPaperInfo.getExamNumber()+1);
            this.updateById(testPaperInfo);
            /*自动交卷任务*/
            String userName = getUserInfo().getUserName();
            DateTime date = DateUtil.offset(DateUtil.date(), DateField.MINUTE, testPaperInfo.getExamTime());
            Map<String, String>  map = new HashMap<>();
            map.put("examInfoId",examInfo.getId());
            quartzTaskScheduler.startCronJobDate("examAutoCommitScheduler", date,map,userName+":自动交卷任务");
        }

        TestPaperQuestionRequest testPaperQuestionRequest = new TestPaperQuestionRequest();
        testPaperQuestionRequest.setTestPaperInfoId(testPaperInfoId);
        Page<TestPaperQuestionDto> page = new Page<>(pageParam.getPageNumber(), pageParam.getPageSize());
        return selectPage(baseMapper.selectPaperQuestionList(page, testPaperQuestionRequest));
    }
    /**
     * 获取试卷详情--用于修改
     * @param testPaperInfoId
     * @return
     */
    public TestPaperInfoVo getTestPaperInfo(String testPaperInfoId) {
        TestPaperInfoVo vo = new TestPaperInfoVo();
        TestPaperInfo testPaperInfo = getById(testPaperInfoId);
        BeanUtil.copyProperties(testPaperInfo,vo);
        List<TestPaperUser> list = testPaperUserService.list(Wrappers.<TestPaperUser>lambdaQuery().eq(TestPaperUser::getTestPaperInfoId, testPaperInfoId));
        List<TestPaperArea> list1 = testPaperAreaService.list(Wrappers.<TestPaperArea>lambdaQuery().eq(TestPaperArea::getTestPaperInfoId, testPaperInfoId));
        vo.setUserJson(list);
        vo.setAreaJson(list1);
        return vo;
    }

    /**
     * 修改试卷试题分数或者排序
     * @param testPaperQuestionDto
     */
    @Transactional(rollbackFor = Exception.class)
    public void updatePaperQuestionMarkOrSort(TestPaperQuestionDto testPaperQuestionDto) {
        // 更新试卷总分
        if (ObjectUtils.isNotEmpty(testPaperQuestionDto.getUpdateType()) &&
                testPaperQuestionDto.getUpdateType().intValue() == ResultCode.SUCCESS) {
            TestPaperInfo testPaperInfo = this.getById(testPaperQuestionDto.getTestPaperInfoId());
            int testPaperInfoMark = testPaperInfo.getMark();
            TestPaperQuestionInfo testPaperQuestionInfo =  testPaperQuestionInfoService.getOne(Wrappers.<TestPaperQuestionInfo>lambdaQuery()
                    .eq(TestPaperQuestionInfo::getQuestionInfoId,testPaperQuestionDto.getQuestionInfoId())
                    .eq(TestPaperQuestionInfo::getTestPaperInfoId,testPaperQuestionDto.getTestPaperInfoId()));
            if (testPaperQuestionInfo.getMark() == 0) {
                testPaperInfo.setMark(testPaperQuestionDto.getMark() + testPaperInfoMark);
            } else {
                testPaperInfoMark -= testPaperQuestionInfo.getMark();
                testPaperInfoMark += testPaperQuestionDto.getMark();
                testPaperInfo.setMark(testPaperInfoMark);
            }
            this.updateById(testPaperInfo);
        }else{
            //不走上面逻辑就不改分
            testPaperQuestionDto.setMark(null);
        }
        LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate(TestPaperQuestionInfo.class)
                .eq(TestPaperQuestionInfo::getQuestionInfoId, testPaperQuestionDto.getQuestionInfoId())
                .eq(TestPaperQuestionInfo::getTestPaperInfoId, testPaperQuestionDto.getTestPaperInfoId())
                .set(testPaperQuestionDto.getMark()!=null,TestPaperQuestionInfo::getMark, testPaperQuestionDto.getMark())
                .set(TestPaperQuestionInfo::getSort, testPaperQuestionDto.getSort());
        testPaperQuestionInfoService.update(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdate(TestPaperInfo testPaperInfo) {
        if (testPaperInfo.getId() != null && testPaperInfo.getExamNumber() > 0) {
            throw new BusinessException(new ResultCode(ResultCode.FAIL, "试卷已被使用, 无法修改"));
        }
        boolean b = super.saveOrUpdate(testPaperInfo);
        testPaperAreaService.remove(Wrappers.<TestPaperArea>lambdaQuery().eq(TestPaperArea::getTestPaperInfoId,testPaperInfo.getId()));
        testPaperUserService.remove(Wrappers.<TestPaperUser>lambdaQuery().eq(TestPaperUser::getTestPaperInfoId,testPaperInfo.getId()));
        if(testPaperInfo.getType()==1){
            String users = testPaperInfo.getUsers();
            boolean json = JSONUtil.isJson(users);
            if(!json){
                throw new BusinessException(new ResultCode(ResultCode.FAIL, "users-json格式错误"));
            }
            JSONArray objects = JSONUtil.parseArray(users);
            List<TestPaperUser> testPaperUsers = objects.toList(TestPaperUser.class);
            testPaperUsers.forEach(x->{
                x.setTestPaperInfoId(testPaperInfo.getId());
            });
            testPaperUserService.saveBatch(testPaperUsers);
        }else{
            String[] split = testPaperInfo.getAreaCodes().split(",");
            List<String> strings = Arrays.asList(split);
            List<TestPaperArea> collect = strings.stream().map(x -> {
                return new TestPaperArea(testPaperInfo.getId(),x);
            }).collect(Collectors.toList());
            testPaperAreaService.saveBatch(collect);
        }
        return b;
    }




    @Transactional
    public ResultCode deleteById(String id) {
        TestPaperInfo testPaperInfo = super.getById(id);
        if (testPaperInfo.getExamNumber() == 0) {
            super.removeById(id);
            // 删除试卷试题关联信息
            testPaperQuestionInfoService.deleteByTestPaperInfoId(id);
            return new ResultCode(ResultCode.SUCCESS, "删除成功");
        }
        return new ResultCode(ResultCode.FAIL, "试卷已被使用, 无法删除");
    }

    public ResultCode publishTestPaperInfo(String testPaperInfoId) {
        TestPaperInfo testPaperInfo = super.getById(testPaperInfoId);
        if (testPaperInfo.getPublishFlag()) {
            return new ResultCode(ResultCode.FAIL, "试卷已发布,请勿重复操作");
        }

        boolean flag = testPaperQuestionInfoService.hasTestPaperInfoQuestion(testPaperInfoId);
        if (!flag) {
            return new ResultCode(ResultCode.FAIL, "改试卷暂未关联试题,请关联试题之后在发布");
        }

        testPaperInfo.setPublishFlag(true);
        testPaperInfo.setPublishTime(new Date());
        super.updateById(testPaperInfo);
        return new ResultCode(ResultCode.SUCCESS, "发布成功");
    }

    public ResultCode cancelTestPaperInfo(String testPaperInfoId) {
        TestPaperInfo testPaperInfo = super.getById(testPaperInfoId);
        if (testPaperInfo.getExamNumber() > 0) {
            return new ResultCode(ResultCode.FAIL, "试卷已有学员作答, 无法撤回");
        }
        testPaperInfo.setPublishFlag(false);
        super.updateById(testPaperInfo);
        return new ResultCode(ResultCode.SUCCESS, "撤销成功");
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveTestPaperInfoQuestion(List<TestPaperQuestionInfo> testPaperQuestionInfoList) {
        Date now = new Date();
        String testPaperInfoId = testPaperQuestionInfoList.get(0).getTestPaperInfoId();
        // 更新试卷试题数量
        TestPaperInfo testPaperInfo = super.getById(testPaperInfoId);
        int questionNumber = testPaperInfo.getQuestionNumber() + testPaperQuestionInfoList.size();
        testPaperInfo.setQuestionNumber(questionNumber);
        super.updateById(testPaperInfo);
        // 保存试卷试题
        testPaperQuestionInfoService.saveBatch(testPaperQuestionInfoList);
    }

    /**
     * 删除试卷试题
     * @param testPaperQuestionInfo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultCode removePaperQuestion(TestPaperQuestionInfo testPaperQuestionInfo) {
        String testPaperInfoId = testPaperQuestionInfo.getTestPaperInfoId();
        TestPaperInfo testPaperInfo = super.getById(testPaperInfoId);
        if (testPaperInfo.getExamNumber() > 0) {
            return new ResultCode(ResultCode.FAIL, "试卷已被使用,无法移除试题");
        }
        testPaperQuestionInfoService.remove(Wrappers.<TestPaperQuestionInfo>lambdaQuery()
            .eq(TestPaperQuestionInfo::getQuestionInfoId,testPaperQuestionInfo.getQuestionInfoId())
            .eq(TestPaperQuestionInfo::getTestPaperInfoId,testPaperInfoId)
        );
//        testPaperQuestionInfoService.removeById(testPaperQuestionInfo.getId());
        // 更新试卷试题数量
        int questionNumber = testPaperInfo.getQuestionNumber() - 1;
        int mark = testPaperInfo.getMark() - testPaperQuestionInfo.getMark();
        testPaperInfo.setQuestionNumber(questionNumber);
        LambdaUpdateWrapper updateWrapper = Wrappers.<TestPaperInfo>lambdaUpdate()
                .set(TestPaperInfo::getQuestionNumber, questionNumber)
                .set(TestPaperInfo::getMark, mark)
                .eq(TestPaperInfo::getId, testPaperInfoId);
        super.update(updateWrapper);
        return new ResultCode(ResultCode.SUCCESS, "删除成功");
    }

    /**
     * 更新考试人数
     * @param testPaperInfoId
     * @return
     */
    public boolean updateExamNumber(String testPaperInfoId) {
        // 更新考试参考人数
        TestPaperInfo testPaperInfo = super.getById(testPaperInfoId);
        int examNumber = testPaperInfo.getExamNumber() + 1;
        LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(TestPaperInfo.class)
                .set(TestPaperInfo::getExamNumber, examNumber)
                .eq(TestPaperInfo::getId, testPaperInfo.getId());
        return super.update(updateWrapper);
    }

    /**
     * 对试卷试题进行分组
     * @param testPaperQuestionDtoList
     * @return
     */
    public List<Map> groupQuestion(List<TestPaperQuestionDto> testPaperQuestionDtoList) {
        List<Map> testPaperQuestionGroupList = new ArrayList<>();
        for (EnumConstants.QuestionType questionType : EnumConstants.QuestionType.values()) {
            Map item = new HashMap<>();
            int questionTypeValue = questionType.getValue();
            List<TestPaperQuestionDto> groupQuestionList = testPaperQuestionDtoList.stream()
                    .filter(question -> question.getQuestionType().getValue() == questionTypeValue)
                    .collect(Collectors.toList());
            item.put("groupQuestionTypeTitle", questionType.getName());
            item.put("groupQuestionList", groupQuestionList);
            testPaperQuestionGroupList.add(item);
        }
        return testPaperQuestionGroupList;
    }



}
